package com.mac.intellect_flow.framework.util;

import com.mac.intellect_flow.base.UserBaseDto;
import com.mac.intellect_flow.constant.CommonConstant;
import com.mac.intellect_flow.enums.ResultCodeEnum;
import com.mac.intellect_flow.except.ServiceException;
import com.mac.intellect_flow.redis.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class JwtUtil {

    //token字符串有效时间
    private static long tokenExpiration = 60*60*1000;
    //加密编码秘钥
    private static String tokenSignKey = "AFS$TE#%B$%##FT@RWRcc";

    private static final long MILLIS_MINUTE_TEN = 10 * 60 * 1000;

    public static String TOKEN_NAME = "X-Token";

    public static RedisUtil redisUtil;

    @Value("${token.secret:}")
    private void setTokenSignKey(String tokenSignKeyConf) {
        if (StringUtils.hasText(tokenSignKeyConf)){
            JwtUtil.tokenSignKey = tokenSignKeyConf;
        }
    }

    @Value("${token.expireTime:60}")
    public void setTokenExpiration(Long tokenExpirationConf) {
        if (tokenExpirationConf > 0){
            JwtUtil.tokenExpiration = tokenExpirationConf * 60*1000;
        }
    }

    @Autowired
    public void setRedisUtil(RedisUtil redisUtil) {
        JwtUtil.redisUtil = redisUtil;
    }


    /**
     *  根据userid  和  username 生成token字符串
     */
    public static String createToken(Long userId, String userName) {

        return Jwts.builder()
                .setSubject("flow")
                .claim("userId",userId)
                .claim("userName",userName)
                .signWith(SignatureAlgorithm.HS256,tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)
                .compact();

    }

    /**
     * 获取请求token
     *
     * @param request
     * @return token
     */
    public static String getToken(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (StringUtils.hasText(token) && token.startsWith(CommonConstant.TOKEN_PREFIX)) {
            token = token.replace(CommonConstant.TOKEN_PREFIX, "");
        }
        return token;
    }

    public static String getPortalLoginRedisKey(String token) {
        if(StringUtils.isEmpty(token)) {
            return "";
        }
        Claims claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        Long userId = (Long)claimsJws.get("userId");
        return CommonConstant.PORTAL_LOGIN_TOKEN_KEY + userId+":"+token.hashCode();
    }

    public static String getAdminLoginRedisKey(String token) {
        if(StringUtils.isEmpty(token)) {
            return "";
        }
        Claims claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        Long userId = claimsJws.get("userId",Long.class);
        return CommonConstant.ADMIN_LOGIN_TOKEN_KEY + userId+":"+token.hashCode();
    }

    /**
     * 验证令牌有效期，相差不足10分钟，自动刷新缓存（也可以自己通过redis缓存一个超时时间）
     *
     * @param token
     * @param userInfo
     */
    public static void verifyToken(String token,boolean isAdmin, UserBaseDto userInfo) {
        if (userInfo == null){
            throw new ServiceException(ResultCodeEnum.LOGIN_EXPIRED);
        }
        long currentTime = System.currentTimeMillis();
        Long expireTime = 0L;
        expireTime = userInfo.getExpireTime();
        if (expireTime < currentTime) {
            throw new ServiceException(ResultCodeEnum.LOGIN_EXPIRED);
        }
        userInfo.setExpireTime(currentTime+tokenExpiration);
        if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
            String loginRedisKey = "";
            if (isAdmin){
                loginRedisKey = getAdminLoginRedisKey(token);
            }else {
                loginRedisKey = getPortalLoginRedisKey(token);
            }
            redisUtil.setCacheObject(loginRedisKey,userInfo,tokenExpiration,TimeUnit.SECONDS);
        }
    }


    /**
     * 设置redis用户信息
     * @param token 如果有token，则使用token，否则从request中获取
     */
    public static void setRedisUserInfo(HttpServletRequest request,String token,UserBaseDto userInfo,boolean isAdmin) {
        if (Objects.nonNull(userInfo)) {
            if (StringUtils.isEmpty(token)){
                token = getToken(request);
                if (StringUtils.isEmpty(token)){
                    throw new ServiceException(ResultCodeEnum.TOKEN_EMPTY);
                }
            }
            long currentTime = System.currentTimeMillis();
            userInfo.setExpireTime(currentTime+tokenExpiration);
            String loginRedisKey = "";
            if (isAdmin){
                loginRedisKey = getAdminLoginRedisKey(token);
            }else {
                loginRedisKey = getPortalLoginRedisKey(token);
            }
            redisUtil.setCacheObject(loginRedisKey,userInfo,tokenExpiration,TimeUnit.SECONDS);
        }
    }

    /**
     * 删除redis用户信息
     * @param token 如果有token，则使用token，否则从request中获取
     */
    public static void delRedisLoginUser(HttpServletRequest request,String token,boolean isAdmin) {
        if (StringUtils.isEmpty(token)){
            token = getToken(request);
            if (StringUtils.isEmpty(token)){
                throw new ServiceException(ResultCodeEnum.TOKEN_EMPTY);
            }
        }
        String loginRedisKey = "";
        if (isAdmin){
            loginRedisKey = JwtUtil.getAdminLoginRedisKey(token);
        }else {
            loginRedisKey = JwtUtil.getPortalLoginRedisKey(token);
        }
        redisUtil.deleteObject(loginRedisKey);
    }

    /**
     *从token字符串获取userId
     * @param request
     * @return
     */
    public static Long getUserId(HttpServletRequest request) {
        String token = getToken(request);
        if (StringUtils.isEmpty(token)){
            throw new ServiceException(ResultCodeEnum.TOKEN_EMPTY);
        }
        Claims claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        Long userId = claimsJws.get("userId",Long.class);
        return userId;
    }
    /**
     *  从token字符串获取getUserName
     */
    public static String getUserName(HttpServletRequest request) {
        String token = getToken(request);
        if (StringUtils.isEmpty(token)){
            throw new ServiceException(ResultCodeEnum.TOKEN_EMPTY);
        }
        Claims claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody();
        return claimsJws.get("userName",String.class);
    }
}
